import { API } from '@v/utils/API';
import { AnyKey } from '@p/utils';
import { useRootStore } from '../store';
import { ImageInfo } from '@p/main-windowObject';
import { escapeHTML, escapeRegExp } from './escape';
import { getImgInfoItemById } from './getImgInfoItem';

const store = useRootStore();

/**
 * 获取属性字符串 key1="…" key2="…" ……
 */
function getAttributeStr(obj: AnyKey<string>) {
	const keys = Object.keys(obj);

	return keys.map((i) => i + `="${obj[i]}"`).join(' ');
}

/**
 * 获取labeldom结构
 */
function getLabelNode(obj: ImageInfo) {
	const classList = ['md-image-label'];

	const attribute = {
		'data-id': obj.id.toString(),
	};

	const attributeStr = getAttributeStr(attribute);

	const reg1 = /^!\[.*\]\([^\s]+\)$/;
	const reg2 = /(!\[.*\]\()([^\s]+)(\))/;
	const reg3 = /(\<img[^>]*src=")([^\s]+)("[^>]*\/?\>)/;
	const arr = [];

	if (reg1.test(obj.initial)) {
		const matchs = obj.initial.match(reg2);
		if (matchs) arr.push(...matchs.slice(1, 4));
	} else {
		const matchs = obj.initial.match(reg3);
		if (matchs) arr.push(...matchs.slice(1, 4));
	}

	const partList = arr.map((item, i) => {
		let calss = 'part-item part-' + (i + 1);

		if (i === 1) {
			calss += ' path';
		}

		if (i === 1 && obj.type === 'base64URL') {
			calss += ' base64URL';

			return `<span class="${calss}">base64URL…</span>`;
		}

		return `<span class="${calss}">${escapeHTML(item)}</span>`;
	});

	return `<span class="${classList.join(' ')}" ${attributeStr}>${partList.join('')}</span>`;
}
/**
 * 获取imgdom结构
 */
function getImgNode(obj: ImageInfo, match: string) {
	// 匹配出img的每个属性
	const attributeRegExp = /(\w+)\s*=\s*("[^"]*"|'[^']*')/g;
	const attribute: AnyKey<string> = {
		// 给img标签设置id
		'data-id': obj.id + '',

		// 给img标签添加事件
		onload: 'mdImageOnloadFn(event)',
		onerror: 'mdImageOnloadErrorFn(event)',
	};

	let tmp = attributeRegExp.exec(match);
	while (tmp !== null) {
		attribute[tmp[1]] = tmp[2].replace(/(^['"]|['"]$)/g, '');
		tmp = attributeRegExp.exec(match);
	}

	// 如果是绝对路径或相对路径就将src设置为本地引用路径
	switch (obj.type) {
		case 'absolute':
		case 'relative':
			attribute.src = obj.localReference as string;
			break;
	}

	const attributeStr = getAttributeStr(attribute);

	return `<img processed ${attributeStr}>`;
}
/**
 * 获取父元素dom结构
 */
function getParentNode(obj: ImageInfo, labelNode: string, imgNode: string) {
	const classList = ['md-image'];

	const attribute = {
		'data-id': obj.id.toString(),
		'data-type': obj.type,
	};

	const attributeStr = getAttributeStr(attribute);

	return `<span class="${classList.join(' ')}" ${attributeStr}>\n\t${labelNode}\n\t${imgNode}\n</span>`;
}

/**
 * 插入加载图片错误图标
 */
function insertErrorIcon(event: ErrorEvent) {
	const imgNode = event.target as HTMLImageElement;
	const labelNode = (imgNode.parentNode as HTMLElement).querySelector('.md-image-label') as HTMLElement;

	if (!labelNode.querySelector('i.load-error-icon')) {
		const node = document.createElement('i');

		node.title = '图片加载失败';

		node.classList.add('iconfont', 'icon-tupian-jiazaishibai', 'load-error-icon');

		labelNode.insertBefore(node, labelNode.firstChild);
	}
}

/**
 * 设置加载结果的属性
 */
function setLoadResultAttribute(event: Event, result: boolean, loadType?: ImageInfo['loadType']) {
	const parentNode = (event.target as HTMLImageElement).parentNode as HTMLElement;

	parentNode.setAttribute('loadResult', result.toString());

	if (result) {
		parentNode.setAttribute('loadType', loadType as string);
	}
}

/**
 * 图片加载成功处理函数
 */
function imageLoad(event: Event, id: number) {
	const item = getImgInfoItemById(id);

	// 设置图片加载类型
	let loadType = 'unknown';
	if (item) {
		switch (item.type) {
			case 'url':
				loadType = 'url';
				break;
			case 'absolute':
			case 'relative':
				loadType = 'localReference';
				break;
		}
	}

	setLoadResultAttribute(event, true, loadType as ImageInfo['loadType']);

	store.setImgInfo_loadResult(id, true, loadType as ImageInfo['loadType']);
}

/**
 * 图片加载失败处理函数
 */
function imageLoadError(event: ErrorEvent, id: number) {
	const item = getImgInfoItemById(id);

	setLoadResultAttribute(event, false);

	store.setImgInfo_loadResult(id, false);

	// 如果图片是url则继续通过主进程加载
	if (item && item.type === 'url') {
		API.invoke('load-network-image', item.target).then((res) => {
			if (res) {
				store.setImgInfo_base64URL(id, res.base64URL);
				(event.target as HTMLImageElement).src = res.base64URL;

				setLoadResultAttribute(event, true, 'base64URL');

				store.setImgInfo_loadResult(id, true, 'base64URL');
			} else {
				insertErrorIcon(event);
			}
		});
	} else {
		insertErrorIcon(event);
	}
}

window.onmdImageOnload(imageLoad);
window.onmdImageOnloadError(imageLoadError);

/**
 * 获取img标签正则字符串
 */
function getImgRegExpString(str: string) {
	return `<img[^>]*src="${str}"[^>]*\\/?>`;
}

/**
 * 替换函数回调
 */
function replaceCallback(item: ImageInfo) {
	let s = false;

	return function (match: string) {
		if (s || / processed /.test(match)) {
			return match;
		} else {
			s = true;

			const imgNode = getImgNode(item, match);
			const labelNode = getLabelNode(item);
			const parentNode = getParentNode(item, labelNode, imgNode);

			return parentNode;
		}
	};
}

export function setMdImgDom(content: string) {
	const arr: ImageInfo['type'][] = ['absolute', 'relative', 'url'];

	if (store.fileInfo) {
		store.fileInfo.imageInfo.forEach((item) => {
			if (arr.includes(item.type)) {
				let nodeSrc1 = escapeRegExp(item.target),
					nodeSrc2 = encodeURI(item.target);

				// 正则字符串
				const regStr1 = getImgRegExpString(nodeSrc1);
				const regStr2 = getImgRegExpString(nodeSrc2);

				// 生成正则
				const reg1 = new RegExp(regStr1, 'g');
				const reg2 = new RegExp(regStr2, 'g');

				const callback = replaceCallback(item);

				// 替换
				content = content.replace(reg1, callback).replace(reg2, callback);
			} else if (item.type === 'base64URL') {
				const regStr = getImgRegExpString(
					escapeRegExp(item.target.slice(0, 100)) + `.{${item.target.length - 100}}`
				);

				const reg = new RegExp(regStr, 'g');

				const callback = replaceCallback(item);

				// 替换
				content = content.replace(reg, callback);
			}
		});

		return content;
	} else {
		return '';
	}
}
